// excerpts from http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef MUDUO_NET_BUFFER_H
#define MUDUO_NET_BUFFER_H

#include "datetime/copyable.h"

#include <algorithm>
#include <string>
#include <vector>

#include <assert.h>

namespace learnmuduo
{

/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer       // Buffer 类仿照 Netty 的 ChannelBuffer
///
/// @code
/// +-------------------+------------------+------------------+
/// | prependable bytes |  readable bytes  |  writable bytes  |
/// |                   |     (CONTENT)    |                  |
/// +-------------------+------------------+------------------+
/// |                   |                  |                  |
/// 0      <=      readerIndex   <=   writerIndex    <=     size
/// @endcode
class Buffer : public muduo::copyable
{
 public:
  static const size_t kCheapPrepend = 8;                             // 默认预留前缀空间
  static const size_t kInitialSize = 1024;                           // 默认初始容量

  Buffer()
    : buffer_(kCheapPrepend + kInitialSize),                         // 分配初始缓冲区
      readerIndex_(kCheapPrepend),                                   // 读指针初始指向前缀末尾
      writerIndex_(kCheapPrepend)                                    // 写指针初始指向前缀末尾
  {
    assert(readableBytes() == 0);                                    // 确认初始无可读数据
    assert(writableBytes() == kInitialSize);                         // 确认可写空间为初始容量
    assert(prependableBytes() == kCheapPrepend);                     // 确认前缀空间可用
  }

  // default copy-ctor, dtor and assignment are fine

  void swap(Buffer& rhs)
  {
    buffer_.swap(rhs.buffer_);                                       // 交换底层存储
    std::swap(readerIndex_, rhs.readerIndex_);                       // 交换读指针
    std::swap(writerIndex_, rhs.writerIndex_);                       // 交换写指针
  }

  size_t readableBytes() const
  { return writerIndex_ - readerIndex_; }                            // 可读数据长度

  size_t writableBytes() const
  { return buffer_.size() - writerIndex_; }                          // 可写空间长度

  size_t prependableBytes() const
  { return readerIndex_; }                                           // 可用于前置数据的空间

  const char* peek() const
  { return begin() + readerIndex_; }                                 // 当前可读数据起始地址

  // retrieve returns void, to prevent
  // string str(retrieve(readableBytes()), readableBytes());
  // the evaluation of two functions are unspecified
  void retrieve(size_t len)
  {
    assert(len <= readableBytes());                                  // 确保读取长度合法
    readerIndex_ += len;                                             // 前移读指针
  }

  void retrieveUntil(const char* end)
  {
    assert(peek() <= end);                                           // 确保目标地址在可读范围
    assert(end <= beginWrite());                                     // 确保未越过写指针
    retrieve(end - peek());                                          // 读取至目标位置
  }

  void retrieveAll()
  {
    readerIndex_ = kCheapPrepend;                                    // 重置读指针
    writerIndex_ = kCheapPrepend;                                    // 重置写指针
  }

  std::string retrieveAsString()
  {
    std::string str(peek(), readableBytes());                        // 拷贝可读数据
    retrieveAll();                                                   // 清空缓冲区
    return str;                                                      // 返回字符串
  }

  void append(const std::string& str)
  {
    append(str.data(), str.length());                                // 重用指针版本
  }

  void append(const char* /*restrict*/ data, size_t len)
  {
    ensureWritableBytes(len);                                        // 确保有足够空间
    std::copy(data, data+len, beginWrite());                         // 拷贝数据到缓冲区
    hasWritten(len);                                                 // 更新写指针
  }

  void append(const void* /*restrict*/ data, size_t len)
  {
    append(static_cast<const char*>(data), len);                     // 转换后调用
  }

  void ensureWritableBytes(size_t len)
  {
    if (writableBytes() < len)                                       // 空间不足时扩展
    {
      makeSpace(len);                                                // 分配或搬移空间
    }
    assert(writableBytes() >= len);                                  // 确认扩展成功
  }

  char* beginWrite()
  { return begin() + writerIndex_; }                                 // 写指针位置（非 const）

  const char* beginWrite() const
  { return begin() + writerIndex_; }                                 // 写指针位置（const）

  void hasWritten(size_t len)
  { writerIndex_ += len; }                                           // 写入完成后推进写指针

  void prepend(const void* /*restrict*/ data, size_t len)
  {
    assert(len <= prependableBytes());                               // 确保前缀空间足够
    readerIndex_ -= len;                                             // 回退读指针
    const char* d = static_cast<const char*>(data);                  // 转换数据指针
    std::copy(d, d+len, begin()+readerIndex_);                       // 拷贝到前缀区域
  }

  void shrink(size_t reserve)
  {
   std::vector<char> buf(kCheapPrepend+readableBytes()+reserve);     // 重新分配较小缓冲
   std::copy(peek(), peek()+readableBytes(), buf.begin()+kCheapPrepend); // 保留现有可读数据
   buf.swap(buffer_);                                                // 替换底层存储
  }

  /// Read data directly into buffer.
  ///
  /// It may implement with readv(2)
  /// @return result of read(2), @c errno is saved
  ssize_t readFd(int fd, int* savedErrno);                           // 从文件描述符读取数据

 private:

  char* begin()
  { return &*buffer_.begin(); }                                      // 获取底层数组首地址

  const char* begin() const
  { return &*buffer_.begin(); }                                      // const 版本

  void makeSpace(size_t len)
  {
    if (writableBytes() + prependableBytes() < len + kCheapPrepend)  // 总空闲不足以容纳新数据
    {
      buffer_.resize(writerIndex_+len);                              // 直接扩容
    }
    else
    {
      // move readable data to the front, make space inside buffer
      assert(kCheapPrepend < readerIndex_);                          // 确保可以搬移
      size_t readable = readableBytes();                             // 保存可读长度
      std::copy(begin()+readerIndex_,
                begin()+writerIndex_,
                begin()+kCheapPrepend);                              // 将可读数据移动到前缀之后
      readerIndex_ = kCheapPrepend;                                  // 重置读指针
      writerIndex_ = readerIndex_ + readable;                        // 重置写指针
      assert(readable == readableBytes());                           // 校验搬移后长度一致
    }
  }

 private:
  std::vector<char> buffer_;                                         // 底层存储容器
  size_t readerIndex_;                                               // 读指针索引
  size_t writerIndex_;                                               // 写指针索引
};

}

#endif  // MUDUO_NET_BUFFER_H
